package test.bl;

import java.util.BitSet;
import java.util.HashSet;
import java.util.List;

import hyl.base.cache.redis.CRedis;
import hyl.base.cache.redis.RedisPool;

/**
 * 改进了网上的例子
 * 
 * @author 37798955@qq.com
 *
 */
public class Bloom {

	public static final String REDISBLOOM = "BLOOM_FILTER_WORDS_DICTIONARY";
	/**
	 * BKRD Hash算法seed
	 */
	private int[] _seeds;
	/*
	 * 不同哈希函数的种子，一般取质数 seeds数组共有8个值，则代表采用8种不同的哈希函数
	 */
	public static final int[] MINSEEDS = new int[] { 3, 5, 7, 11, 13, 31, 37, 61 };
	// 32 个值
	public static final int[] MIDSEEDS = new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61,
			67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131 };

	public int[] getSeed() {
		return _seeds;
	}

	public void setSeed(int[] seed) {
		this._seeds = seed;
	}



	/**
	 * 所需bitMap 位数 为2的幂次方
	 */
	public static Bloom getInstance(int pow) {
		Bloom boolmfilter = new Bloom(MINSEEDS, pow);
		return boolmfilter;
	}

	public static Bloom getInstance() {
		Bloom boolmfilter = new Bloom(MINSEEDS, (1 << 29));
		return boolmfilter;
	}

	// CRedis _rd;
	// 总的bitmap大小 64M
	/**
	 * 所需bitMap 位数 为2的幂次方
	 */

	int _cap;
	BitSet _bs;

	/**
	 * 初始化容量 redis中位图的容量
	 *
	 * @param correctRatio
	 * @param n            输入量
	 */
	public Bloom(int[] seed, int cap) {
		this._seeds = seed;
		this._cap = cap;
		// _rd = RedisPool.getInstance().getRedis("redis1");
		/*
		 * 如果correctRatio.getSeed().length 为32 即有32个hash函数对一个数做映射 那么 bitSet中 32位代表一个数
		 * 所需要的最大容量为32*n
		 */

		_bs = new BitSet();
	}

	public int hash(byte[] value, int seed) {
		int result = 0;
		int length = value.length;
		for (int i = 0; i < length; i++) {
			result = seed * result + value[i];
		}
		// 求余数 防止redis中bitMap无限膨胀 类似循环队列 可以防止系统OOM
		return ((_cap - 1) & result);
	}

	/**
	 * 添加
	 *
	 * @param value
	 */
	public void add(byte[] value) {

		for (int seed : this._seeds) {
			int hash = hash(value, seed);
			_bs.set(hash);
		}

		// _rd.multiSetBit(REDISBLOOM, true, offsets);
	}

	/**
	 * 包含
	 *
	 * @param value
	 * @return
	 */
	public Boolean contain(byte[] word) {

		for (int i = 0; i < this._seeds.length; i++) {
			int hash = hash(word, this._seeds[i]);
			if (!_bs.get(hash))
				return false;
		}
		return true;
	}

}
